/// <reference path="../typings/jquery/jquery.d.ts" />
/// <reference path="../typings/knockout/knockout.d.ts" />

module disco.core {

    export class DataManager<T> {
        private data: T = null;

        constructor() {
        }

        public get(): T {
            return this.data;
        }

        public set(value: T): T {
            return this.data = value;
        }
    }
}

//why not disco.core? => quicker access
module disco {
    export class Namespace {
        public static remove(object: string) {
            return object.substr("Disco.Ontology.".length);
        }
    }

    export class Collections {
        public static contains<T>(collection: T[], predicate: (item: T, index: number) => boolean): boolean {
            var result: any[] = jQuery.grep(collection, predicate);
            return result.length > 0;
        }

        public static where<T>(collection: T[], predicate: (item: T, index: number) => boolean): T[] {
            var result: T[] = jQuery.grep(collection, predicate);
            return result;
        }

        public static single<T>(collection: T[], predicate: (item: T, index: number) => boolean): T {
            var result: any = Collections.nullableSingle(collection, predicate);
            if (result)
                return result;
            else
                throw new Error('The given predicate did not match one single item!');
        }

        public static nullableSingle<T>(collection: T[], predicate: (item: T, index: number) => boolean): T {
            var result: any[] = jQuery.grep(collection, predicate);
            if (result.length == 1)
                return result[0];
            else if (result.length == 0)
                return null;
            else
                throw new Error('The given predicate matched more than one item!');
        }

        public static select<T>(collection: T[], selector: (item: T) => any[]): any[] {
            var result: any[] = [];

            for (var item in collection) {
                result.push(selector(collection[item]));
            }

            return result;
        }

        public static implode(collection: any[], delimiter: string): string {
            var ret = '';

            collection.forEach(elem => {
                if (ret != '')
                    ret += delimiter;
                ret += elem;
            });

            return ret;
        }
    }

    export class Callbacks {
        public static batch(batch: { (onReady): void }[], onFinish: () => void = null) {
            var _batch = (i: number) => {
                if (batch.length > i)
                    batch[i](_batch.bind(null, i + 1));
                else if (onFinish)
                    onFinish();
            };
            _batch(0);
        }

        public static allAtOnce(callbacks: { (onReady): void }[], onFinish: () => void = null) {

            var i = callbacks.length;

            if (i <= 0) {
                if (onFinish) onFinish();
            }

            var finishCallback = () => {
                if (--i <= 0 && onFinish) onFinish();
            };

            callbacks.forEach(cb => {
                var ready = false;
                cb(() => {
                    if (!ready) {
                        ready = true;
                        finishCallback();
                    }
                });
            });
        }
    }

    export class Type {
        public static get(variable): string {
            return Object.prototype.toString.call(variable);
        }
    }

    export class Filters {
        public static valueToOdata(value: any) {
            if (typeof value == 'number')
                return (<number>value).toString();
            if (typeof value == 'string')
                return "'" + value + "'";
            else throw new Error();
        }
    }
}